﻿using System;
using System.Collections.Generic;

using DigitalQuran.Collection;
using DigitalQuran.Extensions;
using DigitalQuran.Data.Metadata;
using System.Text;

namespace DigitalQuran
{
    #region Bowing
    /// <summary>
    /// Bowing of Qur'an
    /// </summary>
    public class Bowing : VerseSpan
    {
        /// <summary>
        /// Create new instance of <see cref="DigitalQuran.Bowing"/>
        /// </summary>
        /// <param name="index">Zero based index of bowing in Qur'an</param>
        /// <param name="startVerse">Bowing First Verse Number</param>
        /// <param name="totalVerses">Total verses in Bowing</param>
        public Bowing(int index, int startVerse, int totalVerses)
            : base(startVerse, totalVerses)
        {
            GlobalNumber = index + 1;

            foreach (var verse in Verses)            
                verse.Bowing = this;            
        }
    }
    #endregion

    #region Chapter
    /// <summary>
    /// Revelation Place of Chapter
    /// </summary>
    public enum RevelationPlace : byte
    {
        /// <summary>
        /// The Makkah City. Value : 0
        /// </summary>        
        Makkah = 0,

        /// <summary>
        /// The Madina City. Value : 1
        /// </summary>
        Medina = 1
    }

    /// <summary>
    /// Chapter of Qur'an
    /// </summary>
    public class Chapter : VerseSpan
    {
        /// <summary>
        /// Minimum Number of Verses a chapter can has
        /// </summary>
        public const int MinVerse = 3;

        /// <summary>
        /// Maximum Number of Verses a chapter can has
        /// </summary>
        public const int MaxVerse = 286;

        /// <summary>
        /// Create new instance of <see cref="DigitalQuran.Chapter"/>
        /// </summary>
        /// <param name="index">Zero based index of chapter in Qur'an</param>
        /// <param name="meta"><see cref="DigitalQuran.Data.Metadata.ChapterMeta"/> instance holding information about chapter</param>
        public Chapter(int index, ChapterMeta meta)
            : base(meta.StartVerse, meta.VerseCount)
        {
            GlobalNumber = index + 1;
            Name = meta.Name;
            TransliteratedName = meta.TransliteratedName;
            EnglishName = meta.EnglishName;
            RevelationOrder = meta.RevelationOrder;
            RevelationPlace = meta.RevelationPlace;
            BowingCount = meta.BowingCount;

            foreach (var verse in this.Verses)            
                verse.Chapter = this;

        }

        /// <summary>
        /// Gets the Value of this Chapter
        /// </summary>
        public long Value { get; internal set; }

        /// <summary>
        /// Gets the Arabic Name of Chapter
        /// </summary>
        public string Name { get; private set; }

        /// <summary>
        /// Gets the Transliterated Name of Chapter
        /// </summary>
        public string TransliteratedName { get; private set; }

        /// <summary>
        /// Gets the English Name of Chapter
        /// </summary>
        public string EnglishName { get; private set; }

        /// <summary>
        /// Gets the Revelation Order of Chapter
        /// </summary>
        public int RevelationOrder { get; private set; }

        /// <summary>
        /// Gets the Revelation Place of Chapter
        /// </summary>
        public RevelationPlace RevelationPlace { get; private set; }

        /// <summary>
        /// Gets the Number of Bowings
        /// </summary>
        public int BowingCount { get; private set; }


        public override int GetCount(QuranObjectType objType)
        {
            if (objType == QuranObjectType.Bowing)
                return BowingCount;

            return base.GetCount(objType);
        }

        public override IQuranObject GetObject(QuranObjectType objType, int index)
        {
            if (objType == QuranObjectType.Bowing)
                return BowingCollection.GetBowing(this.FirstVerse.Bowing.GlobalNumber - 1 + index);

            return base.GetObject(objType, index);
        }
    }

    #endregion

    #region Group
    /// <summary>
    /// Group of Qur'an
    /// </summary>
    public class Group : VerseSpan
    {
        /// <summary>
        /// Creates new instance of <see cref="DigitalQuran.Group"/>
        /// </summary>
        /// <param name="index">Zero based index of Group in Qur'an</param>
        /// <param name="startVerse">First verse number of Group</param>
        /// <param name="totalVerses">Total Verses in Group</param>
        public Group(int index, int startVerse, int totalVerses)
            : base(startVerse, totalVerses)
        {
            GlobalNumber = index + 1;

            foreach (var verse in this.Verses)            
                verse.Group = this;            
        }

        public override int GetCount(QuranObjectType objType)
        {
            switch (objType)
            {
                case QuranObjectType.Bowing:
                    return LastVerse.Bowing.GlobalNumber - FirstVerse.Bowing.GlobalNumber + 1;
                case QuranObjectType.Quarter:
                    return 2;
            }

            return base.GetCount(objType);
        }

        public override IQuranObject GetObject(QuranObjectType objType, int index)
        {
            switch (objType)
            {
                case QuranObjectType.Bowing:
                    return Book.Instance.Bowings[FirstVerse.Bowing.GlobalNumber - 1 + index];
                case QuranObjectType.Quarter:
                    return Book.Instance.Quarters[FirstVerse.Quarter.GlobalNumber - 1 + index];
            }

            return base.GetObject(objType, index);
        }
    }
    #endregion

    #region Page
    /// <summary>
    /// Page of Qur'an
    /// </summary>
    public class Page : VerseSpan
    {
        /// <summary>
        /// Create new instance of <see cref="DigitalQuran.Page"/>
        /// </summary>
        /// <param name="index">Zero based index of page in Qur'an</param>
        /// <param name="startVerse">Page First Verse Number</param>
        /// <param name="totalVerses">Total verses in Page</param>
        public Page(int index, int startVerse, int totalVerses)
            : base(startVerse, totalVerses)
        {
            GlobalNumber = index + 1;

            foreach (var verse in this.Verses)
            {
                verse.Page = this;
            }
        }
    }
    #endregion

    #region Part
    /// <summary>
    /// Part of Qur'an
    /// </summary>
    public class Part : VerseSpan
    {
        /// <summary>
        /// Creates new intance of <see cref="DigitalQuran.Part"/>
        /// </summary>
        /// <param name="index">Zeo based index in Qur'an</param>
        /// <param name="meta">Meta Data of Part</param>
        public Part(int index, PartMeta meta)
            : base(meta.StartVerse, meta.VerseCount)
        {
            GlobalNumber = index + 1;

            Name = meta.ArabicName;
            TransliteratedName = meta.TransliteratedName;

            foreach (var verse in this.Verses)
                verse.Part = this;
        }

        /// <summary>
        /// Get the Arabic Name of Part
        /// </summary>
        public string Name { get; private set; }

        /// <summary>
        /// Gets the Transliterated Name
        /// </summary>
        public string TransliteratedName { get; private set; }

        public override int GetCount(QuranObjectType objType)
        {
            switch (objType)
            {
                case QuranObjectType.Bowing:
                    return LastVerse.Bowing.GlobalNumber - FirstVerse.Bowing.GlobalNumber + 1;
                case QuranObjectType.Group:
                    return 2;
                case QuranObjectType.Quarter:
                    return 4;
            }

            return base.GetCount(objType);
        }

        public override IQuranObject GetObject(QuranObjectType objType, int index)
        {
            switch (objType)
            {
                case QuranObjectType.Bowing:
                    return Book.Instance.Bowings[FirstVerse.Bowing.GlobalNumber + index];
                case QuranObjectType.Group:
                    return Book.Instance.Groups[(GlobalNumber - 1) * 2 + index];
                case QuranObjectType.Quarter:
                    return Book.Instance.Quarters[(GlobalNumber - 1) * 4 + index];
            }

            return base.GetObject(objType, index);
        }
    }
    #endregion

    #region Prostration
    /// <summary>
    /// Type of Qur'an Prostration
    /// </summary>
    public enum ProstrationType : byte
    {
        /// <summary />
        Recommended = 0,
        /// <summary />        
        Obligatory = 1
    }

    /// <summary>
    /// Prostration in Qur'an
    /// </summary>
    public class Prostration : IQuranObject
    {
        internal Prostration(int index, int verseNo, ProstrationType type)
        {
            GlobalNumber = index + 1;
            Type = type;

            Verse = VerseCollection.GetVerse(verseNo - 1);
        }

        public int GlobalNumber { get; private set; }

        /// <summary>
        /// Gets Type of Prostration
        /// </summary>
        public ProstrationType Type { get; private set; }

        /// <summary>
        /// Gets the Prostation Verse
        /// </summary>
        public Verse Verse { get; private set; }

        public int GetCount(QuranObjectType objType)
        {
            switch (objType)
            {
                case QuranObjectType.Word:
                    return this.Verse.Words.Count;
                case QuranObjectType.Letter:
                    return this.Verse.Words.LetterCount;
            }

            return -1;
        }

        public IQuranObject GetObject(QuranObjectType objType, int index)
        {
            switch (objType)
            {
                case QuranObjectType.Word:
                    return Verse.Words[index];
                case QuranObjectType.Letter:
                    return null;
            }

            return null;
        }

        public string ToString(string textMode)
        {
            return Verse.ToString(textMode);
        }
    }
    #endregion

    #region Quarter
    /// <summary>
    /// Qur'an Quarter
    /// </summary>
    public class Quarter : VerseSpan
    {
        /// <summary>
        /// Creates new instance of <see cref="DigitalQuran.Quarter"/>
        /// </summary>
        /// <param name="index">Zero based index in Qura'n</param>
        /// <param name="startVerse">First Verse Number of Quarter</param>
        /// <param name="count">Total Verses in Qur'an</param>
        public Quarter(int index, int startVerse, int count)
            : base(startVerse, count)
        {
            GlobalNumber = index + 1;

            foreach (var verse in this.Verses)
                verse.Quarter = this;
        }

        public override int GetCount(QuranObjectType objType)
        {
            switch (objType)
            {
                case QuranObjectType.Bowing:
                    return LastVerse.Bowing.GlobalNumber - FirstVerse.Bowing.GlobalNumber + 1;
            }

            return base.GetCount(objType);
        }

        public override IQuranObject GetObject(QuranObjectType objType, int index)
        {
            switch (objType)
            {
                case QuranObjectType.Bowing:
                    return Book.Instance.Bowings[FirstVerse.Bowing.GlobalNumber + index - 1];
            }

            return base.GetObject(objType, index);
        }
    }
    #endregion

    #region Station
    /// <summary>
    /// Qur'an Station
    /// </summary>
    public class Station : VerseSpan
    {
        /// <summary>
        /// Craetes new instance of <see cref="DigitalQuran.Station"/>
        /// </summary>
        /// <param name="index">Zero based index in Qur'an</param>
        /// <param name="startVerse">First Verse number in Qur'an</param>
        /// <param name="count">Total verses in Station</param>
        public Station(int index, int startVerse, int count)
            : base(startVerse, count)
        {
            GlobalNumber = index + 1;

            foreach (var verse in this.Verses)
            {
                verse.Station = this;
            }
        }

        public override int GetCount(QuranObjectType objType)
        {
            switch (objType)
            {
                case QuranObjectType.Chapter:
                    return LastVerse.Chapter.GlobalNumber - FirstVerse.Chapter.GlobalNumber + 1;
                case QuranObjectType.Group:
                    return LastVerse.Group.GlobalNumber - FirstVerse.Group.GlobalNumber + 1;
                case QuranObjectType.Quarter:
                    return LastVerse.Quarter.GlobalNumber - FirstVerse.Quarter.GlobalNumber + 1;
                case QuranObjectType.Bowing:
                    return LastVerse.Bowing.GlobalNumber - FirstVerse.Bowing.GlobalNumber + 1;
            }

            return base.GetCount(objType);
        }

        public override IQuranObject GetObject(QuranObjectType objType, int index)
        {
            switch (objType)
            {
                case QuranObjectType.Chapter:
                    return Book.Instance.Chapters[FirstVerse.Chapter.GlobalNumber + index - 1];
                case QuranObjectType.Group:
                    return Book.Instance.Groups[FirstVerse.Group.GlobalNumber + index - 1];
                case QuranObjectType.Quarter:
                    return Book.Instance.Quarters[FirstVerse.Quarter.GlobalNumber + index - 1];
                case QuranObjectType.Bowing:
                    return Book.Instance.Bowings[FirstVerse.Bowing.GlobalNumber + index - 1];
            }

            return base.GetObject(objType, index);
        }
    }
    #endregion

    #region VerseSpan

    /// <summary>
    /// Represent Qur'an Objects made up of Verses
    /// </summary>
    public class VerseSpan : IQuranObject
    {
        protected VerseSpan(int startVerse, int count)
        {
            Verses = new VerseCollection(startVerse - 1, count);
        }

        public VerseCollection Verses { get; protected set; }

        public int GlobalNumber { get; protected set; }

        public Verse LastVerse
        {
            get
            {
                return Verses[Verses.Count - 1];
            }
        }

        public Verse FirstVerse
        {
            get
            {
                return Verses[0];
            }
        }

        public virtual IQuranObject GetObject(QuranObjectType objType, int index)
        {
            switch (objType)
            {
                case QuranObjectType.Verse:
                    return this.Verses[index];
                case QuranObjectType.Word:
                    return this.Verses.GetWord(index);
                case QuranObjectType.Letter:
                    return null;
            }

            return null;
        }

        public virtual int GetCount(QuranObjectType objType)
        {
            switch (objType)
            {
                case QuranObjectType.Verse:
                    return this.Verses.Count;
                case QuranObjectType.Word:
                    return this.Verses.WordCount;
                case QuranObjectType.Letter:
                    return this.Verses.LetterCount;
            }

            return -1;
        }

        /// <summary>
        /// Ruturns Text of All Verses for specified text mode. Returns Empty String if text mode is invalid
        /// </summary>
        /// <param name="mode">Text Mode</param>
        /// <returns></returns>
        public string ToString(string mode)
        {
            var strBuilder = new StringBuilder();
            foreach (var verse in this.Verses)
            {
                strBuilder.AppendLine(verse.ToString(mode));
            }

            return strBuilder.ToString();
        }
    }
    #endregion

    #region Verse
    /// <summary>
    /// Qur'an Verse
    /// </summary>
    public class Verse : IQuranObject
    {
        /// <summary>
        /// Creates new instance of Verse
        /// </summary>
        /// <param name="number">Zero based index of Verse in Qur'an</param>
        /// <param name="firstWordIndex">Zero based index of First Word in Qur'an</param>
        /// <param name="words">Array of Verse Words</param>
        public Verse(int number, int firstWordIndex, string[] words)
        {
            GlobalNumber = number + 1;

            Words = new WordCollection(firstWordIndex, words, this);            
        }

        /// <summary>
        /// Gets the verse number in Qur'an
        /// </summary>
        public int GlobalNumber { get; private set; }

        public IQuranObject GetObject(QuranObjectType objType, int index)
        {
            switch (objType)
            {
                case QuranObjectType.Word:
                    return Words[index];
            }

            return null;
        }

        public int GetCount(QuranObjectType objType)
        {
            switch (objType)
            {
                case QuranObjectType.Word:
                    return Words.Count;
            }

            return -1;
        }

        /// <summary>
        /// Gets the Distance to previous verse
        /// </summary>
        public Distance DistanceToPrevious { get; internal set; }

        /// <summary>
        /// Gets collection of words
        /// </summary>
        public WordCollection Words { get; private set; }

        /// <summary>
        /// Gets the Value of Verse
        /// </summary>
        public long Value { get; internal set; }

        /// <summary>
        /// Gets the bowing containing Verse
        /// </summary>
        public Bowing Bowing { get; internal set; }

        /// <summary>
        /// Gets the Goup containing Verse
        /// </summary>
        public Group Group { get; internal set; }

        /// <summary>
        /// Gets the Chapter containing Verse
        /// </summary>
        public Chapter Chapter { get; internal set; }

        /// <summary>
        /// Gets the Part containing Verse
        /// </summary>
        public Part Part { get; internal set; }

        /// <summary>
        /// Gets the Station containing Verse
        /// </summary>
        public Station Station { get; internal set; }

        /// <summary>
        /// Gets the Quarter containing Verse
        /// </summary>
        public Quarter Quarter { get; internal set; }

        /// <summary>
        /// Gets the Page containing verse
        /// </summary>
        public Page Page { get; internal set; }

        /// <summary>
        /// Gets the Prostration detail if verse is prostration verse else return null
        /// </summary>
        public Prostration Prostration { get; internal set; }

        Address? _Address = null;
        /// <summary>
        /// Gets Address of Verse
        /// </summary>
        public Address Address
        {
            get
            {
                if (!_Address.HasValue)
                    _Address = Address.Create(Chapter.GlobalNumber, NumberInChapter);

                return _Address.Value;
            }
        }

        int? _NumberInChapter = null;
        /// <summary>
        /// Gets the Verse Number in Chapter
        /// </summary>
        public int NumberInChapter
        {
            internal set { _NumberInChapter = value; }
            get
            {
                if (!_NumberInChapter.HasValue)
                    NumberInChapter = GlobalNumber - Chapter.FirstVerse.GlobalNumber + 1;

                return _NumberInChapter.GetValueOrDefault(-1);
            }
        }

        /// <summary>
        /// Gets Unique Letters in this Verse
        /// </summary>
        public List<Letter> UniqueLetters
        {
            get
            {
                var _UniqueLetters = new List<Letter>();
                foreach (Word word in Words)
                    foreach (Letter letter in word.Letters)
                        if (!_UniqueLetters.Contains(letter))
                        {
                            _UniqueLetters.Add(letter);
                        }

                return _UniqueLetters;
            }
        }

        /// <summary>
        /// Gets the Text Associated with verse for <see cref="DigitalQuran.Collection.WordCollection.CurrentTextMode"/> text mode
        /// </summary>
        public string ActiveText { get; internal set; }

        /// <summary>
        /// Gets the verse text for specified text mode
        /// </summary>
        /// <param name="mode">Text mode</param>
        /// <returns>Returns the verse text for specified text mode if valid text mode else return <see cref="System.String.Empty"/></returns>
        public string ToString(string mode)
        {
            if (mode == WordCollection.CurrentTextMode)
                return ActiveText;

            return Words.ToString(mode);
        }
    }
    #endregion
    
    #region Word
    /// <summary>
    /// Qur'an Word
    /// </summary>
    public class Word : IQuranObject
    {
        /// <summary>
        /// Create new instance of <see cref="DigitalQuran.Word"/>
        /// </summary>
        /// <param name="number">Zero based index of Word in Qur'an</param>
        /// <param name="verse">Parent Verse of Word</param>
        public Word(int number, Verse verse)
        {
            GlobalNumber = number + 1;
            Verse = verse;

            if (Globals.Edition == Edition.Grammar) {
                Parts = new WordPartCollection();
            }
        }

        /// <summary>
        /// Gets Word Number in Qur'an
        /// </summary>
        public int GlobalNumber { get; private set; }

        /// <summary>
        /// Gets the Verse in Which Word Exists
        /// </summary>
        public Verse Verse { get; private set; }

        /// <summary>
        /// Gets List of WordPart. (Only Available in Grammer Edition)
        /// </summary>
        public WordPartCollection Parts { get; private set; }

        /// <summary>
        /// Gets the Word Number in Qur'an Chapter
        /// </summary>
        public int NumberInChapter { get; internal set; }

        /// <summary>
        /// Gets the Word Number in Verse
        /// </summary>
        public int NumberInVerse { get; internal set; }

        internal Distance _DistanceToPrevious = new Distance();
        /// <summary>
        /// Gets the Distance to Previous Verse
        /// </summary>
        public Distance DistanceToPrevious { get { return _DistanceToPrevious; } }

        /// <summary>
        /// Gets value of word
        /// </summary>
        public long Value { get; internal set; }

        Address? _Address = null;
        /// <summary>
        /// Gets <see cref="DigitalQuran.Address"/> of Word
        /// </summary>
        public Address Address
        {
            get
            {
                if (!_Address.HasValue)
                    _Address = Address.Create(Verse.Chapter.GlobalNumber, Verse.NumberInChapter, NumberInVerse);

                return _Address.Value;
            }
        }

        /// <summary>
        /// Gets the Uthmani Qur'an Text Word Meaning
        /// </summary>
        public string Meaning { get; internal set; }

        /// <summary>
        /// Gets the Uthmani Qur'an Text Roots
        /// </summary>
        public string[] Roots { get; internal set; }

        LetterCollection _Letters = null;
        /// <summary>
        /// Gets Collection of Letters of this Word
        /// </summary>
        public LetterCollection Letters
        {
            get
            {
                if (_Letters == null)
                    _Letters = new LetterCollection(GlobalNumber - 1);

                return _Letters;
            }
        }

        List<Letter> _UniqueLetters = null;
        /// <summary>
        /// Gets Collection of Unique Letters of this Word
        /// </summary>
        public List<Letter> UniqueLetters
        {
            get
            {
                if (_UniqueLetters == null)
                {
                    _UniqueLetters = new List<Letter>();
                    foreach (Letter letter in this.Letters)
                    {
                        if (!_UniqueLetters.Contains(letter))
                            _UniqueLetters.Add(letter);
                    }
                }

                return _UniqueLetters;
            }
        }

        /// <summary>
        /// Returns the Text of Word for Specified TextMode. Returns Empty String If TextMode is invalid
        /// </summary>
        /// <param name="textMode">Text Mode</param>
        /// <returns></returns>
        public string ToString(string textMode)
        {
            return WordCollection.GetText(GlobalNumber - 1, textMode);
        }

        public int GetCount(QuranObjectType objType)
        {
            switch (objType)
            {
                case QuranObjectType.Letter:
                    return Letters.Count;
            }

            return -1;
        }

        public IQuranObject GetObject(QuranObjectType objType, int index)
        {
            switch (objType)
            {
                case QuranObjectType.Letter:
                    return Letters[index];
            }

            return null;
        }

        /// <summary>
        /// Gets Corpus Roots of Word
        /// </summary>
        public string CorpusRoot
        {
            get
            {
                var s = new StringBuilder();
                foreach (WordPart part in this.Parts)
                {
                    if (!string.IsNullOrEmpty(part.Features.Root))
                    {
                        s.Append(part.Features.Root.ToArabic());
                        s.Append("|");
                    }
                }

                if (s.Length > 0)
                    s.Remove(s.Length - 1, 1);  // remove leading '|'

                return s.ToString();
            }
        }

        /// <summary>
        /// Gets Corpus Lemma of Words
        /// </summary>
        public string CorpusLemma
        {
            get
            {
                var corpusLemma = new StringBuilder();
                foreach (WordPart part in this.Parts)
                {
                    if (!String.IsNullOrEmpty(part.Features.Lemma))
                    {
                        corpusLemma.Append(part.Features.Lemma.ToArabic());
                        corpusLemma.Append("|");
                    }
                }

                if (corpusLemma.Length > 0)
                    corpusLemma.Remove(corpusLemma.Length - 1, 1);  // remove leading '|'

                return corpusLemma.ToString();
            }
        }

        /// <summary>
        /// Gets Special Group Corpus of Word
        /// </summary>
        public string CorpusSpecialGroup
        {
            get
            {
                var s = new StringBuilder();

                foreach (var part in this.Parts)
                {
                    if (!String.IsNullOrEmpty(part.Features.SpecialGroup))
                        s.Append(part.Features.SpecialGroup.ToArabic() + "|");
                }

                if (s.Length > 0)
                    s = s.Remove(s.Length - 1, 1);

                return s.ToString();
            }
        }

        /// <summary>
        /// Gets Arabic Grammer of Word
        /// </summary>
        public string ArabicGrammar
        {
            get
            {
                StringBuilder result = new StringBuilder();

                var str = new StringBuilder();
                var previousWordParAddress = new Address();
                for (int i = 0; i < this.Parts.Count; i++)
                {
                    if (previousWordParAddress == this.Parts[i].Word.Address)
                        str.Append(this.Parts[i].ToArabic() + "\r\n");                    // continue with current word
                    else // new word
                    {
                        previousWordParAddress = this.Parts[i].Word.Address;

                        // finish up previous word
                        if (str.Length > 2)
                        {
                            str.Remove(str.Length - 2, 2);
                            result.Append(str.ToString());
                            // clear str for new word
                            str.Length = 0;
                        }

                        // continue with current word
                        str.Append(this.Parts[i].ToArabic() + "\r\n");
                    }

                    if (i == this.Parts.Count - 1)
                    {
                        // finish up last word
                        if (str.Length > 2)
                        {
                            str.Remove(str.Length - 2, 2);
                            result.Append(str.ToString());
                        }
                    }
                }

                return result.ToString();
            }
        }

        /// <summary>
        /// Gets English Grammer of Word
        /// </summary>
        public string EnglishGrammar
        {
            get
            {
                StringBuilder result = new StringBuilder();

                var str = new StringBuilder();
                var previousWordPartAddress = new Address();

                for (int i = 0; i < this.Parts.Count; i++)
                {
                    if (previousWordPartAddress == this.Parts[i].Word.Address)
                    {
                        // continue with current word
                        str.Append(this.Parts[i].ToEnglish() + "\r\n");
                    }
                    else // new word
                    {
                        previousWordPartAddress = this.Parts[i].Word.Address;

                        // finish up previous word
                        if (str.Length > 2)
                        {
                            str.Remove(str.Length - 2, 2);
                            result.Append(str.ToString());
                            // clear str for new word
                            str.Length = 0;
                        }

                        // continue with current word
                        str.Append(this.Parts[i].ToEnglish() + "\r\n");
                    }

                    if (i == this.Parts.Count - 1)
                    {
                        // finish up last word
                        if (str.Length > 2)
                        {
                            str.Remove(str.Length - 2, 2);
                            result.Append(str.ToString());
                        }
                    }
                }

                return result.ToString();
            }
        }

        /// <summary>
        /// Gets Grammer of Word
        /// </summary>
        public string Grammar
        {
            get
            {
                StringBuilder result = new StringBuilder();

                StringBuilder str = new StringBuilder();
                Address previousWordPartAddress = new Address();
                for (int i = 0; i < this.Parts.Count; i++)
                {
                    if (previousWordPartAddress == this.Parts[i].Word.Address)
                    {
                        // continue with current word
                        str.Append(this.Parts[i].ToGrammar() + "\r\n");
                    }
                    else // new word
                    {
                        previousWordPartAddress = this.Parts[i].Word.Address;

                        // finish up previous word
                        if (str.Length > 2)
                        {
                            str.Remove(str.Length - 2, 2);
                            result.Append(str.ToString());
                            // clear str for new word
                            str.Length = 0;
                        }

                        // continue with current word
                        str.Append(this.Parts[i].ToGrammar() + "\r\n");
                    }

                    if (i == this.Parts.Count - 1)
                    {
                        // finish up last word
                        if (str.Length > 2)
                        {
                            str.Remove(str.Length - 2, 2);
                            result.Append(str.ToString());
                        }
                    }
                }

                return result.ToString();
            }
        }

        /// <summary>
        /// Gets Occurances of this word in Qur'an for specified text mode upto this word
        /// </summary>
        /// <param name="textMode">Text mode for which to search</param>
        /// <returns>Returns word occurances count in Qur'an</returns>
        public int GetOccurrenceUptoThis(string textMode)
        {
            int occurrence = 0;
            string thisText = this.ToString(textMode);

            bool stop = false;
            foreach (Verse verse in Book.Instance.Verses)
            {
                if (!stop)
                {
                    foreach (var word in verse.Words)
                    {
                        if (word.ToString(textMode) == thisText)
                            occurrence++;

                        if (word == this)
                        {
                            stop = true;
                            break;
                        }
                    }
                }
            }

            return occurrence;
        }

        /// <summary>
        /// Counts All occurances of word in Qur'an for specified text mode
        /// </summary>
        /// <param name="textMode">text mode in which to search</param>
        /// <returns>Returns occurances count in Qur'an</returns>
        public int GetAllOccurrences(string textMode)
        {
            int occurrences = 0;
            string thisText = this.ToString(textMode);

            foreach (Verse verse in Book.Instance.Verses)
                foreach (var word in verse.Words)
                    if (word.ToString(textMode) == thisText)
                        occurrences++;

            return occurrences;
        }

        /// <summary>
        /// Gets Transliteration of Word
        /// </summary>
        public object Transliteration { get; set; }
    }
    #endregion

    #region Letter
    public class Letter : IQuranObject
    {
        internal Letter(Word word, char character)
        {
            Word = word;
            Character = character;

            _DistanceToPrevious = new Distance();
        }

        /// <summary>
        /// Gets Character of this Letter
        /// </summary>
        public char Character { get; private set; }

        /// <summary>
        /// Gets the Parent Word
        /// </summary>
        public Word Word { get; private set; }

        /// <summary>
        /// Gets the Number in Qur'an
        /// </summary>
        public int GlobalNumber { get; internal set; }

        /// <summary>
        /// Gets the Number in Chapter
        /// </summary>
        public int NumberInChapter { get; internal set; }

        /// <summary>
        /// Gets the Number in Verse
        /// </summary>
        public int NumberInVerse { get; internal set; }

        /// <summary>
        /// Gets the Number in Word
        /// </summary>
        public int NumberInWord { get; set; }

        internal Distance _DistanceToPrevious;
        /// <summary>
        /// Distance to Previous Letter
        /// </summary>
        public Distance DistanceToPrevious { get { return _DistanceToPrevious; } }

        /// <summary>
        /// Gets Value of Letter
        /// </summary>
        public long Value { get; internal set; }

        public override string ToString()
        {
            return "Letter " + GlobalNumber.ToString();
        }

        public IQuranObject GetObject(QuranObjectType objType, int index)
        {
            return null;
        }

        public int GetCount(QuranObjectType objType)
        {
            return -1;
        }

        public string ToString(string textMode)
        {
            return null;
        }
    }
    #endregion
}